package com.company.bookstore.schedule;

/**
 * 如何动态的开启定时任务
 * 为什么不用Spring Schedule ， 无法调度其开始关闭
 *
 * 超简单使用redisson延迟队列做定时任务
 * https://blog.csdn.net/ZuiChuDeQiDian/article/details/104374110
 *
 *
 * https://blog.csdn.net/noaman_wgs/article/details/80984873
 * https://www.w3cschool.cn/quartz_doc/quartz_doc-h4ux2cq6.html
 * 上面三个部分就是Quartz的基本组成部分：
 *
 * 调度器：Scheduler
 * 任务：JobDetail
 * 触发器：Trigger，包括SimpleTrigger和CronTrigger
 * JobDetail定义的是任务数据，而真正的执行逻辑是在Job中。
 * 这是因为任务是有可能并发执行，如果Scheduler直接使用Job，就会存在对同一个Job实例并发访问的问题。
 * 而JobDetail & Job 方式，Sheduler每次执行，都会根据JobDetail创建一个新的Job实例，这样就可以规避并发访问的问题。
 *
 * JobExecutionContext中包含了Quartz运行时的环境以及Job本身的详细数据信息。
 * 当Schedule调度执行一个Job的时候，就会将JobExecutionContext传递给该Job的execute()中，Job就可以通过JobExecutionContext对象获取信息。
 *
 * Trigger是Quartz的触发器，会去通知Scheduler何时去执行对应Job。
 *
 * new Trigger().startAt():表示触发器首次被触发的时间;
 * new Trigger().endAt():表示触发器结束触发的时间;
 *
 * CronTrigger功能非常强大，是基于日历的作业调度，而SimpleTrigger是精准指定间隔，
 * 所以相比SimpleTrigger，CroTrigger更加常用。CroTrigger是基于Cron表达式的，先了解下Cron表达式：
 * 由7个子表达式组成字符串的，格式如下：
 *
 * [秒] [分] [小时] [日] [月] [周] [年]
 *
 *
 * 需要注意的是一旦调度器调用 了shutdown 方法关闭后，如果不重新实例化，它就不会启动了。触发器在调度器未启动时，或是终止状态时，都不会被触发。
 * Scheduler 的生命期，从 SchedulerFactory 创建它时开始，到 Scheduler 调用shutdown() 方法时结束；
 * Scheduler 被创建后，可以增加、删除和列举 Job 和 Trigger，以及执行其它与调度相关的操作（如暂停 Trigger）。
 * 但是，Scheduler 只有在调用 start() 方法后，才会真正地触发 trigger（即执行 job）
 *
 *
 * 例如，Job 被创建后，可以保存在 Scheduler 中，与 Trigger 是独立的，同一个 Job可以有多个 Trigger；这种松耦合的另一个好处是，
 * 当与 Scheduler 中的 Job 关联的 trigger 都过期时，可以配置 Job 稍后被重新调度，而不用重新定义 Job；还有，可以修改或者替换 Trigger，而不用重新定义与之关联的 Job。
 *
 * Key
 * 将 Job 和 Trigger 注册到 Scheduler 时，可以为它们设置 key，配置其身份属性。 Job 和 Trigger 的 key（JobKey 和 TriggerKey）
 * 可以用于将 Job 和 Trigger 放到不同的分组（group）里，然后基于分组进行操作。同一个分组下的 Job 或 Trigger 的名称必须唯一，
 * 即一个 Job 或 Trigger 的 key 由名称（name）和分组（group）组成。
 *
 *
 *  @DisallowConcurrentExecution：将该注解加到job类上，告诉Quartz不要并发地执行同一个job定义（这里指特定的job类）的多个实例
 *
 *  @PersistJobDataAfterExecution：将该注解加在job类上，告诉Quartz在成功执行了job类的execute方法后（没有发生任何异常），
 *  更新JobDetail中JobDataMap的数据，使得该job（即JobDetail）在下一次执行的时候，JobDataMap中是更新后的数据，而不是更新前的旧数据。
 *  和 @DisallowConcurrentExecution注解一样，尽管注解是加在job类上的，但其限制作用是针对job实例的，而不是job类的。由job类来承载注解，是因为job类的内容经常会影响其行为状态（比如，job类的execute方法需要显式地“理解”其”状态“）。
 *  如果你使用了@PersistJobDataAfterExecution注解，我们强烈建议你同时使用@DisallowConcurrentExecution注解，
 *  因为当同一个job（JobDetail）的两个实例被并发执行时，由于竞争，JobDataMap中存储的数据很可能是不确定的。
 *  Durability：如果一个job是非持久的，当没有活跃的trigger与之关联的时候，会被自动地从scheduler中删除。也就是说，非持久的job的生命期是由trigger的存在与否决定的；
 * RequestsRecovery：如果一个job是可恢复的，并且在其执行的时候，scheduler发生硬关闭（hard shutdown)
 * （比如运行的进程崩溃了，或者关机了），则当scheduler重新启动的时候，该job会被重新执行。此时，该job的JobExecutionContext.isRecovering() 返回true。
 *
 * JobExecutionContext中的JobDataMap为我们提供了很多的便利。它是JobDetail中的JobDataMap和Trigger中的JobDataMap的并集
 *
 * 你可以只创建一个job类，然后创建多个与该job关联的JobDetail实例，每一个实例都有自己的属性集和JobDataMap，最后，将所有的实例都加到scheduler中。
 *
 * 分布式 定时任务
 * 该项目中存在一个定时器模块；如果这里不做特殊处理的话，三台应用型服务器会在同一时刻执行相同的定时器三次
 * 解决方案：
 * XXL-JOB
 * https://gitee.com/xuxueli0323/xxl-job?utm_source=alading&utm_campaign=repo
 * 没找到中文文档
 * cron
 * https://www.cnblogs.com/rever/p/9887384.html
 *
 *
 * */

public class demo {
}
